// --------------------------------------------------------------------
//  ...
// --------------------------------------------------------------------
//  $File: ...
//  $Revision: #1 $
//  $Date: 2012/06/11 $
// --------------------------------------------------------------------
#ifndef RUBIKSCUBE
#define RUBIKSCUBE

#include <cstdlib>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vlgGlutEngine.h>
#include <vlgSolidPlate.h>
#include <vlgGLPointLight.h>
#include "Cuby.h"
#include "rcXMLReader.h"

//! Enum for slice names
enum Face {RIGHT = 0, LEFT = 1, UPPER = 2, DOWN = 3, FRONT = 4, BACK = 5};

//! RubiksCube - A fully functional Rubiks Cube with GLUT
class RubiksCube : public vlgGlutEngine
{
private:
	//! Constructor
	RubiksCube(void);
	//! Instanzvariable (singleton)
	static RubiksCube* instance;
	//! Point light source
	vlgGLPointLight *pointLight;
	//! Mirror pane for the bottom side
	vlgSolidPlate* floorPlane;
	//! Mirror pane for the back side
	vlgSolidPlate* backPlane;
	//! Mirror pane for the left side
	vlgSolidPlate* leftPlane;
	//! "Cubies"
	Cuby cubies[3][3][3];
	//! Indicates the explotion grade of the Rubiks Cube
	float explosionGrade;

	//! Inticate whether the XML file for the excersices exists and if it contains exercises
	bool existExercises;
	//! Excersices for solving the last layer
	std::set<std::string> exercises;

	//! Creates the Cubies for the Rubiks Cube
	void buildCube(void);
	//! Displays the entire Rubiks Cube
	void displayRubiksCube(void);
	//! Swaps slice
	void swapCubes(int participants[][3], Rotation rot);
	//! Draws the bottom mirror pane
	void drawFloor(void);
	//! Draws the back mirror pane
	void drawBack(void);
	//! Draws the left mirror pane
	void drawLeft(void);

	//! save the configuration of the cube
	void saveConfiguration(void);

public:
	//! Returns the instance of the class
	static RubiksCube* Instance(void);
	//! OpenGL initialization 
	void initContext(void);
	//! Function with applicationinstructions for the grafical output
	void display(void);
	//! Keyboard shortcuts for manipulating the Rubiks Cube
    void keyboard(unsigned char key, int x, int y);
	//! Info output
    void about(void);

	//! Rotate right slice (R)
	void rotateRightSlice(Rotation rot);
	//! Rotate middle slice (M)
	void rotateMiddleSlice(Rotation rot);
	//! Rotate left slice (L)
	void rotateLeftSlice(Rotation rot);

	//! Rotate upper slice (U)
	void rotateUpperSlice(Rotation rot);
	//! Rotate equator slice (E)
	void rotateEquatorSlice(Rotation rot);
	//! Rotate down slice (D)
	void rotateDownSlice(Rotation rot);
	
	//! Rotate front slice (F)
	void rotateFrontSlice(Rotation rot);
	//! Rotate standing slice (S)
	void rotateStandingSlice(Rotation rot);
	//! Rotate back slice (B)
	void rotateBackSlice(Rotation rot);

	//! Rotate entire cube on x-axis (X)
	void rotateCubeXAxis(Rotation rot);
	//! Rotate entire cube on y-axis (Y)
	void rotateCubeYAxis(Rotation rot);
	//! Rotate entire cube on z-axis (Z)
	void rotateCubeZAxis(Rotation rot);

	//! Explode Cube ;-)
	void explode(bool increase);

	//! Shuffle Cube with random rotations
	void shuffleCube(int times);
};

#endif /* RUBIKSCUBE */
